import base64
import json
import logging
import datetime
from decimal import Decimal

from Crypto import Random
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA

from base.connection import get_db_session
from common.definition import PayStatus, PayType, OrderStatus, OrderType
from helper.payment.balance import BalanceHandler
from helper.payment.pay_util import BenefitHelper
from helper.payment.wechat_pay import WechatPay
from conf.config import FACTORY_UID

logger = logging.getLogger("payment")


class BaseRefund(object):
    def __init__(self, order_id):
        self.order_id = order_id

    def refund(self):
        raise NotImplementedError


class BalanceRefund(BaseRefund):
    def refund(self):
        order_id = self.order_id

        class GoodsOrder(object):
            pass

        session = get_db_session([
            {"db_table": "sdet_order", "model": GoodsOrder},
        ])
        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).one()
        if order.sdef_order_fee >= Decimal("0.01"):
            logger.error("纯余额订单退款: 失败: 支付方式为余额，但微信金额大于0.01：order_id=%s" % order_id)
            session.close()
            return False
        # 如果是余额支付的话要退余额
        is_ok = BalanceHandler.add_manual_money(order.sdef_order_device_id,
                                                order.sdef_order_balance_fee,
                                                operator=order_id)
        if not is_ok:
            logger.error("纯余额订单退款: 失败: order_id=%s" % order_id)
            session.close()
            return False

        # 余额退款，修改订单状态为已退款
        order.sdef_order_pay_status = PayStatus.REFUND
        session.commit()
        session.close()
        logger.info("纯余额订单退款: 成功: order_id=%s" % order_id)
        return True


class WechatRefund(BaseRefund):
    def refund(self):
        order_id = self.order_id

        class GoodsOrder(object):
            pass

        session = get_db_session([
            {"db_table": "sdet_order", "model": GoodsOrder},
        ])
        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).one()
        is_ok = WechatPay.order_refund(order_id, order.sdef_order_fee)
        if not is_ok:
            logger.error("微信退款失败：order_id=%s" % order_id)
            session.close()
            return False

        if order.sdef_order_balance_fee > Decimal("0"):
            is_ok = BalanceHandler.add_manual_money(order.sdef_order_device_id,
                                                    order.sdef_order_balance_fee,
                                                    operator=order_id)
            if not is_ok:
                logger.error("混合支付的订单余额退款失败：order_id=%s" % order_id)
                session.close()
                return False
        # 修改订单状态为已退款
        order.sdef_order_pay_status = PayStatus.REFUND
        session.commit()
        BenefitHelper.update_benefit_refund(order_id)
        session.close()
        logger.info("微信支付的订单退款成功：order_id=%s" % order_id)
        return True


class CancelOrderRefund(BaseRefund):
    def __init__(self, cipher_text):
        private_key = """-----BEGIN RSA PRIVATE KEY-----
             MIICXAIBAAKBgQCn1B+wnKtMwmBajOBzQBN+QGij+2zczIT8JHaDeRxQ8GKm8bZw
             6T3HHWGWkCeTOHfLj2kZg7CaKB/1XdBf2jp7gD89YzgkIMd1gzcJV1qiP7HtEoh8
             xXnZzWIsenxuzW0wPrNB7F3LvGR9qFmdqWduh8pEyqiG3haDaB342ilmUQIDAQAB
             AoGAVvSNRtCl4KuFiOUdFhnI/80Xan9GtFAzRwENdqk1hqpGMwFh6bavj48llQEz
             wA+t4gZ4CgQ1aGoJxPPKlx9W1PaEs8Y4VyWz+qcPjQHNETf+UGVJXxoHGa6YsI06
             BJSRKQBwka9pHmab2H+swyCIwbe9iasUmZU76lvmIFwVucECQQC7UOvqSz+jIuz9
             N1TcJiIU3yFXyRqUIFTK6rdK6dXkmpkbRoPnt/w+u8rMslyhgq3aGaK+/YpDNLUC
             hq9MjUK1AkEA5V3w43+IvSEMKiAAliZGKwIEqxU8l4i3ihfthtOhshr0Xul8AV6g
             ifnjHMCIyz/Wx5HsQalSt/jRoAAzT59KrQJAdf/rLgRLSXSmAHoLzkeDbsyFT6zT
             Pn8Di3TDFMErykANtV39mEqR798TSVIPAnu1E1DU8iX8JIwef0HjSoEuhQJBAK/h
             HyxzyRit1LQgohKA+uFTxNyjhjj0nzkHLB5s/dqjDKwTAgHS2+uxcFPF159zLnEO
             FkorWsCzzZqRTMdLcGkCQDU2Z8egLD0nqMOXRChGfXPt8+3UgBvwmO665mnk1sGs
             SMCq+xereUchaK0ixErDQA5AbO4eEqxJc4CtQ1rFe8M=
             -----END RSA PRIVATE KEY-----"""

        rsa = RSA.importKey(private_key)
        cipher = PKCS1_v1_5.new(rsa)
        random_generator = Random.new().read
        text = cipher.decrypt(base64.b64decode(cipher_text), random_generator).decode()
        text_json = json.loads(text)
        order_id = text_json["order_id"]
        super(CancelOrderRefund, self).__init__(order_id)
        self.cipher_text = cipher_text

    def refund(self):
        order_id = self.order_id

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        class StoreGoods(object):
            pass

        class CouponUser(object):
            pass

        class CouponOrder(object):
            pass

        class UserInventory(object):
            pass

        session = get_db_session([
            {"db_table": "sdet_order", "model": GoodsOrder},
            {"db_table": "sdet_goods", "model": Goods},
            {"db_table": "sdet_store_goods", "model": StoreGoods},
            {"db_table": "ebt_coupon_user", "model": CouponUser},
            {"db_table": "ebt_coupon_order", "model": CouponOrder},
            {"db_table": "ebt_user_inventory", "model": UserInventory},
        ])
        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).one()
        if order.sdef_order_pay_status != PayStatus.SUCCESS:
            logger.error("支付状态异常:order_id=%s" % order_id)
            return False
        if order.sdef_order_is_delete != 0:
            logger.error("订单已删除:order_id=%s" % order_id)
            return False
        if not (order.sdef_order_status == OrderStatus.CHECK or (
                order.sdef_order_status == OrderStatus.AFTER_SALE
                and order.sdef_order_after_sale_type == 1) or
                order.sdef_order_status == OrderStatus.WAIT_VALID):
            logger.error("只有待审核或退货的订单才能退款:order_id=%s" % order_id)
            return False

        # 取消订货订单退款限制
        # order_type = order.sdef_order_type
        # if order_type == OrderType.PINGUI:
        #     # 拼柜订单退款时判断库存是否符合条件
        #     cart_goods = json.loads(order.sdef_order_goods)
        #     goods_id = cart_goods[0]["id"]
        #     count = cart_goods[0]["count"]
        #     filters2 = dict(
        #         user_id=order.sdef_order_device_id,
        #         goods_id=goods_id,
        #         status=1
        #     )
        #     ui = session.query(UserInventory).filter_by(**filters2).first()
        #     if not ui:
        #         logger.error("用户没有该商品库存记录:order_id=%s" % order_id)
        #         session.close()
        #         return False
        #     inventory = ui.inventory
        #     if inventory < count:
        #         logger.error("用户已取酒:order_id=%s" % order_id)
        #         session.close()
        #         return False

        if order.sdef_order_pay_type == PayType.BALANCE:
            refund_instance = BalanceRefund(order_id)
        elif order.sdef_order_pay_type == PayType.WECHAT:
            refund_instance = WechatRefund(order_id)

        if not order_refund(refund_instance):
            session.close()
            return False
        # todo 是否需要将订单删除？

        # 订单退款成功还原商品库存
        store_id = order.sdef_order_store_id
        order_goods = json.loads(order.sdef_order_goods)
        filters = dict(
            sdef_goods_store_id=store_id,
            sdef_goods_factory_uid=FACTORY_UID
        )

        for g in order_goods:
            if store_id > 0:
                filters["sdef_goods_id"] = g["id"]
                goods = session.query(StoreGoods).filter_by(**filters).first()
            else:
                goods = session.query(Goods).filter_by(sdef_goods_id=g["id"]).first()

            if goods:
                goods.sdef_goods_count += int(g["count"])

        order.sdef_order_status = OrderStatus.INVALID
        try:
            session.query(CouponUser).filter_by(order_id=order_id).update({CouponUser.status: 2})
            logger.info(f"退款后修改优惠券状态为无效order_id={order_id}")
            if order.sdef_order_coupon_fee > Decimal("0"):
                filters3 = dict(
                    user_id=order.sdef_order_device_id,
                    order_id=order_id,
                    status=1
                )
                co = session.query(CouponOrder).filter_by(**filters3).one()
                cu_id = co.coupon_user_id
                cu = session.query(CouponUser).filter_by(id=cu_id).one()
                cu.status = 0
                session.delete(co)
                logger.info(f"还原优惠券成功order_id={order_id}")

            # 取消订货订单退款限制
            # if order_type == OrderType.PINGUI:
            #     # 拼柜订单退款时减少用户商品库存
            #     logger.info(f"refund: old_inventory={ui.inventory} count=-{count}")
            #     if (inventory - count) == 0:
            #         session.delete(ui)
            #     else:
            #         ui.inventory -= count
            #         access_record = json.loads(ui.access_record)
            #         access_record["add"] = []
            #         ui.access_record = json.dumps(access_record)
            #         ui.update_time = datetime.datetime.now()
        except Exception as e:
            logger.error(f"还原优惠券失败order_id={order_id}, error={e}")
        session.commit()
        session.close()
        return True


def order_refund(refund):
    """
    订单退款
    :param refund:  BaseRefund 实例
    :return: boolean
    """
    if not isinstance(refund, BaseRefund):
        raise Exception("必须为 BaseRefund 类型的数据")
    logger.info("订单退款：order_id=%s" % refund.order_id)
    try:
        is_success = refund.refund()
        if is_success:
            BenefitHelper.update_benefit_refund(refund.order_id)
    except Exception as e:
        logger.exception(e)
        is_success = False
    logger.info("订单退款结果：is_success=%s,order_id=%s" % (is_success, refund.order_id))
    return is_success


def cancel_order_immediate_refund(order_id):
    content = '{"order_id": "%s"}' % order_id
    public_key = """-----BEGIN PUBLIC KEY-----
        MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn1B+wnKtMwmBajOBzQBN+QGij
        +2zczIT8JHaDeRxQ8GKm8bZw6T3HHWGWkCeTOHfLj2kZg7CaKB/1XdBf2jp7gD89
        YzgkIMd1gzcJV1qiP7HtEoh8xXnZzWIsenxuzW0wPrNB7F3LvGR9qFmdqWduh8pE
        yqiG3haDaB342ilmUQIDAQAB
        -----END PUBLIC KEY-----"""
    rsa1 = RSA.importKey(public_key)
    cipher1 = PKCS1_v1_5.new(rsa1)
    # 加密
    cipher_text = cipher1.encrypt(content.encode())
    cipher_text = base64.b64encode(cipher_text).decode()
    refund_instance = CancelOrderRefund(cipher_text)
    result = order_refund(refund_instance)
    logger.info("取消订单立即退款结果：order_id=%s,result=%s" % (order_id, result))
    return result